{{define "theme-server-status/network"}}
{{template "theme-server-status/header" .}}
{{template "theme-server-status/menu" .}}
<div class="container-fluid content network-box">
    <div class="network-box-header btn-group">
        <div class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <i class="bi bi-list-ul"></i> {{tr "NetworkSpiterList"}} <i class="bi bi-chevron-compact-down"></i>
        </div>
        <ul class="dropdown-menu">
            <li class="input-group fixed-top">
                <input type="text" id="dropdown-search" class="form-control" placeholder="Search...">
            </li>
            <li class="dropdown-item" v-for="server in servers" @click="showCharts(server.ID)">
                <a><i :class="'fi fi-' + (server.Host.CountryCode || 'un')"></i> @#server.Name#@ <i v-if="server.ID == currentServerId" class="check icon"></i></a>
            </li>
        </ul>
    </div>
    <div v-if="chartTitle" class="chartTitle" @click="showCharts(nextServerId)"><i class="chartCountryCode" :class="'fi fi-' + chartCountryCode"></i> @#chartTitle#@</div>
    <div id="chartbox" style="width:100%;height:auto;"></div>
</div>
{{template "theme-server-status/footer" .}}
<script>
    new Vue({
        el: '#app',
        delimiters: ['@#', '#@'],
        data: {
            page: 'network',
            defaultTemplate: "{{.Conf.Site.Theme}}",
            templates: "{{.Themes }}",
            servers: [],
            chartDataList: [],
            chartTitle: '',
            chartCountryCode: '',
            chart: null,
            currentServerId: '',
            nextServerId: '',
        },
        mixins: [mixinsVue],
        created() {
            this.servers = JSON.parse('{{.Servers}}').servers;
            this.showCharts(this.servers[0].ID);
        },
        mounted() {
            this.initSearch();            
        },
        methods: {
            showCharts(id) {
                // 发起数据请求
                const url = `/api/v1/monitor/${id}`;
                fetch(url)
                    .then(response => response.json())
                    .then(data => {
                        if (data.result) { // 数据请求成功，更新数据并渲染图表
                            this.chartDataList[id] = data.result;
                            this.$nextTick(() => {
                                this.renderCharts(id);
                            });
                        } else {
                            console.log('this server (id:'+ id + ') has no monitor.');
                        }
                    })
                    .catch(error => {
                        console.error('Error fetching data:', error);
                    });
            },
            renderCharts(id, reload = false) {
                if(!this.chartDataList[id]) return;
                if(this.chart) this.disposeCharts(this.chart);
                this.currentServerId = id;
                this.nextServerId = this.getNextServerId(id);
                this.chartCountryCode = this.getServerCountryCode(id);
                this.chartTitle = this.chartDataList[id][0].server_name;
                const chartData = this.chartDataList[id];
                const chartContainer = document.getElementById('chartbox');
                const MaxTCPPingValue = {{.Conf.MaxTCPPingValue}} ? {{.Conf.MaxTCPPingValue}} : 300;
                const autoheight = this.isMobile ? (window.innerHeight - 180) : (window.innerHeight - 250);
                const fontSize = this.isMobile ? 10 : 14;
                const gridLeft = (MaxTCPPingValue > 500) ? (this.isMobile ? 36 : 42) : (this.isMobile ? 30 : 36);
                const gridRight = this.isMobile ? 12 : 20;
                const legendLeft = this.isMobile ? 'center' : 'center';
                const legendTop = this.isMobile ? 5 : 5;
                const legendPadding= this.isMobile ? [5,0,5,0] : [5,0,5,0];
                const fontColor = this.theme == "dark" ? "#f1f1f1" : "#000000";
                const chartTheme = this.theme == "dark" ? "dark" : "default";
                const backgroundColor = this.theme == "dark" ? '' : '';
                const tooltipBackgroundColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.85)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.85)" : "rgba(255,255,255,1)");
                const tooltipBorderColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.9)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.9)" : "rgba(255,255,255,1)");
                const lineStyleWidth = this.isMobile ? 1 : 2;
                const splitLineWidth = this.isMobile ? 0.5 : 1;
                const markPointSymbolSize = this.isMobile ? 36 : 42;
                const markPointItemStyleOpacity = this.semiTransparent ? 1 : 1;
                const markPointFontSize = this.isMobile ? 8 : 10;
                const markLineItemStyleOpacity = this.semiTransparent ? 1 : 0.75;
                const markLineLineStyleWidth = this.isMobile ? 0.15 : 0.3;
                const showLoadingMaskColor = this.theme == "dark" ? 'rgba(0, 0, 0, 0)' : 'rgba(255, 255, 255, 0)';
                const showLoadingTextColor = this.theme == "dark" ? 'rgba(241, 241, 241, 1)' : 'rgba(0, 0, 0, 1)';
                const showLoadingColor = this.theme == "dark" ? '#D2B206' : '#FFDF32';
                this.chart = echarts.init(chartContainer, chartTheme, { // init图表
                    renderer: 'canvas',
                    useDirtyRect: false,
                    width: 'auto',
                    height: autoheight,
                });
                this.chart.showLoading({
                    text: 'loading',
                    textColor: showLoadingTextColor,
                    color: showLoadingColor,
                    maskColor: showLoadingMaskColor,
                    zlevel: 2
                });
                let legendData = [];
                let seriesData = [];
                chartData.forEach((item,key)=> {
                    let loss = 0;
                    let totalLossRate = 0;
                    let legendName = '';
                    let data = { main: [], markLine: []};
                    item.avg_delay.forEach((avgDelay, index) => {
                        const threshold = 0.9 * MaxTCPPingValue; // 定义阀值,用于判断是否丢包
                        // 定义丢包 1. avgDelay==0  2. avgDelay>=MaxTCPPingValue 3. avgDelay>=threshold
                        if(avgDelay == 0 || avgDelay >= MaxTCPPingValue){ //绝对丢包
                            loss += 1;
                            const lossrate = 100 * loss / (index + 1);
                            if(lossrate != 100) {
                                data['markLine'].push({
                                    xAxis: item.created_at[index],
                                    label: { show: false },
                                    emphasis: { disabled: true },
                                    lineStyle: { type: "solid" }
                                });
                            }
                        } else if (avgDelay >= threshold && avgDelay < MaxTCPPingValue){ // 相对丢包
                            loss += 1;
                            const lossrate = 100 * loss / (index + 1);
                            if(lossrate != 100) {
                                data['main'].push(
                                    [item.created_at[index], avgDelay, lossrate]
                                );
                                data['markLine'].push({
                                    xAxis: item.created_at[index],
                                    label: { show: false },
                                    emphasis: { disabled: true },
                                    lineStyle: { type: "solid" }
                                });
                            }
                        } else { // 未丢包
                            const lossrate = 100 * loss / (index + 1);
                            data['main'].push(
                                [item.created_at[index], avgDelay, lossrate]
                            );
                        }
                    });
                    totalLossRate = ((loss / item.created_at.length) * 100).toFixed(1);
                    legendName = `${item.monitor_name} ${totalLossRate}%`;
                    legendData.push(legendName);
                    seriesData.push(
                        {
                            name: legendName,
                            type: 'line',
                            smooth: true,
                            symbol: 'none',
                            connectNulls: true,
                            legendHoverLink: false,
                            emphasis: {
                                disabled: true
                            },
                            lineStyle: {
                                width: lineStyleWidth
                            },  
                            data: data['main'],
                            markLine: {
                                symbol: "none",
                                symbolSize :0,
                                data: data['markLine'],
                                itemStyle: { 
                                    opacity: markLineItemStyleOpacity
                                },
                                lineStyle:{
                                    width: markLineLineStyleWidth
                                }
                            },
                            markPoint: {
                                data: [
                                    { 
                                        name: 'Max',
                                        type: 'max', 
                                        symbol: 'pin', 
                                        itemStyle: { 
                                            opacity: markPointItemStyleOpacity
                                        }, 
                                        symbolSize: markPointSymbolSize, 
                                        label: { 
                                            fontSize: markPointFontSize,
                                            formatter: function (params) {
                                                return Math.round(params.value);
                                            }
                                        }
                                    },
                                    {
                                        name: 'Min',
                                        type: 'min', 
                                        symbol: 'pin', 
                                        itemStyle: { 
                                            opacity: markPointItemStyleOpacity
                                        }, 
                                        symbolSize: markPointSymbolSize, 
                                        label: { 
                                            fontSize: markPointFontSize,
                                            offset: [0, 8],
                                            formatter: function (params) {
                                                return Math.round(params.value);
                                            }
                                        }, 
                                        symbolRotate: 180 
                                    }
                                ]
                            }
                        }
                    );
                });
                const maxLegendsPerRowMobile = localStorage.getItem("maxLegendsPerRowMobile") ? localStorage.getItem("maxLegendsPerRowMobile") : 3;
                const maxLegendsPerRowPc = localStorage.getItem("maxLegendsPerRowPc") ? localStorage.getItem("maxLegendsPerRowPc") : 6;
                const autoIncrement = Math.floor((legendData.length - 1) / (this.isMobile ? maxLegendsPerRowMobile : maxLegendsPerRowPc)) * (this.isMobile ? 20 : 28);
                const height = autoheight + autoIncrement;
                const gridTop = this.isMobile ? ( 60 + autoIncrement) : (80 + autoIncrement);
                const gridBottom = this.isMobile ? 70 : 90;
                const legendIcon = this.isMobile ? 'rect' : ""; 
                const itemWidth = this.isMobile ? 10 : 25;
                const itemHeight = this.isMobile ? 10 : 14;
                this.chart.resize({
                    width: 'auto',
                    height: height
                });
                // 设置图表配置项
                const option = {
                    color: this.colors,
                    backgroundColor: backgroundColor,
                    textStyle: {
                        fontSize: fontSize,
                        color: fontColor
                    },
                    grid: {
                        top: gridTop,
                        left: gridLeft,
                        right: gridRight,
                        bottom: gridBottom
                    },
                    title: {
                        show: false,
                    },
                    series: seriesData.flat(),
                    xAxis: {
                        type: 'time',
                        axisLabel: {
                            textStyle: {
                                fontSize: fontSize
                            }
                        }
                    },
                    yAxis: {
                        type: 'value',
                        axisLabel: {
                            textStyle: {
                                fontSize: fontSize
                            }
                        },
                        splitLine: {
                            lineStyle: {
                                width: splitLineWidth
                            }
                        }
                    },
                    legend: {
                        data: legendData,
                        show: true,
                        icon: legendIcon,
                        textStyle: {
                            fontSize: fontSize,
                            color: fontColor
                        },
                        top: legendTop,
                        bottom: 0,
                        left: legendLeft,
                        padding: legendPadding,
                        itemWidth: itemWidth,
                        itemHeight: itemHeight,
                    },
                    tooltip: {
                        trigger: 'axis',
                        backgroundColor: tooltipBackgroundColor,
                        borderColor: tooltipBorderColor,
                        textStyle: {
                            fontSize: fontSize,
                            color: fontColor
                        },
                        formatter: function (params) {
                            let tooltipContent = '';
                            const formattedTime = new Date(params[0].value[0]).toLocaleString(); 
                            tooltipContent += `<span style="line-height:2em">${formattedTime}</span><br>`;
                            params.forEach(param => {
                                const formattedTime = new Date(param.value[0]).toLocaleString();
                                if (!param.seriesName.includes('stack')) {
                                    const name = param.seriesName.replace(/\s\d+(\.\d+)?%$/, '');
                                    tooltipContent += `<span style="line-height:2em">${param.marker} ${name} ${param.value[2].toFixed(1)}% ${param.value[1].toFixed(2)}</span><br>`;
                                }
                            });
                            return tooltipContent;
                        }
                    },
                    dataZoom: [
                        {
                            type: 'slider',
                            start: 0,
                            end: 100
                        }
                    ]
                };
                setTimeout(() => {
                    this.chart.hideLoading();
                    this.chart.setOption(option);
                }, 1000);
            },
            reloadCharts() {
                const chartData = this.chartDataList[this.currentServerId];
                if (chartData) {
                    this.renderCharts(this.currentServerId,true);
                }
            },
            disposeCharts(chart){
                chart.dispose();
                chart = null;
            },
            getServerCountryCode(id){
                const result = this.servers.find(item => item.ID == id);
                return result.Host.CountryCode ? result.Host.CountryCode : 'un';
            },
            getNextServerId(id) {
                const currentIndex = this.servers.findIndex(item => item.ID === id);
                if (currentIndex === -1) {
                    return this.servers[0].ID;
                }
                // 判断是否有下一个元素
                const nextIndex = currentIndex + 1;
                // 如果有下一个元素，返回下一个元素的 ID；否则返回第一个元素的 ID
                return nextIndex < this.servers.length ? this.servers[nextIndex].ID : this.servers[0].ID;
            },
            initSearch() {
                $('#dropdown-search').on('keyup', function() {
                    var searchTerm = $(this).val().toLowerCase();
                    $('.dropdown-menu .dropdown-item').each(function() {
                        var text = $(this).text().toLowerCase();
                        if (text.indexOf(searchTerm) > -1) {
                            $(this).removeClass('hidden').addClass('visible'); // 显示元素
                        } else {
                            $(this).removeClass('visible').addClass('hidden'); // 隐藏元素
                        }
                    });
                });
            }
        }
    });
</script>
{{end}}
